Apache Commons Digester
在Tomcat
,Spring
等系统框架中,都会出现xml
配置,在最初的Spring
框架中,都是通过xml
文件描述对象信息继而注入到系统中,那xml
是如何转化为JavaBean
的呢?
Digester
是来自Apache Commons
包中的一个项目,最开始发现它是在Tomcat
的源代码中,它主要用来完成以“事件驱动”的方式来处理XML元素,使用它能够很方便的将xml
与JavaBean
映射出来
Demo
下面的例子来自Digester
的官方文档:
- Maven引入需要依赖的包
<dependency>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
<version>1.8</version>
</dependency>
- 新建一个
example.xml
文件
<foo name="The Parent">
<bar id="123" title="The First Child" />
<bar id="456" title="The Second Child" />
<bar id="789" title="The Second Child" />
</foo>
- 新建对应的
Bar
和Foo
类
@Getter
@Setter
public class Bar
{
private int id;
private String title;
}
@Getter
@Setter
public class Foo
{
private String name;
private List<Bar> barList = new ArrayList<Bar>();
public void addBar(Bar bar)
{
barList.add(bar);
}
public Bar findBar(int id)
{
for (Bar bar : barList)
{
if (bar.getId() == id)
{
return bar;
}
}
return null;
}
public Iterator<Bar> getBars()
{
return barList.iterator();
}
}
@Getter和@Setter 来自lombok插件
- 配置Digester使用Digester
public static void main(String[] agrs) throws Exception {
try {
//1、创建Digester对象实例
Digester digester = new Digester();
//2、配置属性值
digester.setValidating(false);
//3、push对象到对象栈
//digester.push(new Foo());
//4、设置匹配模式、规则
digester.addObjectCreate("foo", "com.dengchengchao.digester.Foo");
digester.addSetProperties("foo");
digester.addObjectCreate("foo/bar", "com.dengchengchao.digester.Bar");
digester.addSetProperties("foo/bar");
digester.addSetNext("foo/bar", "addBar", "com.dengchengchao.digester.Bar");
//5、开始解析
Foo foo = (Foo) digester.parse(DigesterTest.class.getResourceAsStream("example.xml"));
//6、打印解析结果
System.out.println(foo.getName());
for (Bar bar : foo.getBarList()) {
System.out.println(bar.getId() + "," + bar.getTitle());
}
} catch (IOException e) {
e.printStackTrace();
}
}
- 输出结果
The Parent
123,The First Child
456,The Second Child
789,The Second Child
可以看到,Foo
和Bar
的属性,通过简单的xml
配置就能够修改属性等。
Digester详解
Digester
最主要是通过栈来操作各个数据结构,在上面的例子中
<foo name="The Parent">
<bar id="123" title="The First Child" />
<bar id="456" title="The Second Child" />
<bar id="789" title="The Second Child" />
</foo>
Digester在解析的时候,首先会创建一个foo
对象,并将对象压入栈中,然后设置栈顶对象foo
属性name
为The Parent
,紧接着创建Bar
对象并压入栈,然后设置栈顶对象id
为123
,title
属性为The First Child
,然后再遇到xml
结束符时,弹出栈顶元素:bar
,依次类推。
最终在解析完xml
后,留在栈顶的对象就关联了所有在xml
解析中创建的动态对象。
Digester元素匹配模式
Digester
是以事件驱动方式处理xml
文件的,它所具有的一个关键特性就是可以自动识别xml
的层次结构,用户只用关心所遇到的元素需要做什么操作即可,例如:
<a> -- Matches pattern "a"
<b> -- Matches pattern "a/b"
<c/> -- Matches pattern "a/b/c"
<c/> -- Matches pattern "a/b/c"
</b>
<b> -- Matches pattern "a/b"
<c/> -- Matches pattern "a/b/c"
<c/> -- Matches pattern "a/b/c"
<c/> -- Matches pattern "a/b/c"
</b>
</a>
Digester 规则处理
当遇到匹配模式的时候,便会触发Digester
对象定义的规则,简单介绍如下:
- 创建类规则
addObjectCreate
//当匹配到foo节点时,创建com.dengchengchao.digester.Foo对象,并压入栈顶 digester.addObjectCreate("foo", "com.dengchengchao.digester.Foo");
addFactoryCreate
//利用指定的工厂类创建一个对象,把对象压入栈。对于没有提供默认构造函数的类,这一规则很有用 //所初始化的对象必须实现AbstractObjectCreationFactory接口 digester.addFactoryCreate("tomcat-users/group", new MemoryGroupCreationFactory(this), true);
- 属性设置类规则
addSetProperties
//给栈顶的对象设置相应节点的属性 //这将调用默认的Setter Getter digester.addSetProperties("foo");
addSetProperty
//无论是Bean属性的名称,还是赋予该属性的值,都在当前XML元素中以属性的形式指定 //例如:<article key="page" value="10" /> digester.addSetProperties("foo");
BeanPropertySetterRule
//把顶层Bean的指定名称的属性设置成当前XML元素包含的字符数据。 //(通常用来处理<page>10</page>之类的结构) digester.addBeanPropertySetter("foo");
- 父/子关系类规则
addSetRoot
//调用栈底对象的一个方法,并把栈顶的对象作为参数传入。 digester.addSetTop("foo/bar","addBar");
addSetTop
//把栈里面上数第二的对象传递给顶层的对象。当子对象提供了一个setParenet方法时,这一规则很有用。 digester.addSetTop("foo/bar","addBar");
addSetNext
//弹出栈顶的对象,把它传递给紧接其下的另一个对象的指定名称的方法 digester.addSetNext("foo/bar", "addBar", "com.dengchengchao.digester.Bar");
- 方法类规则
addCallMethod
-
addCallParam
//调用顶层Bean的指定名称的方法。被调用的方法可以有任意多个参数,参数的值通过后继的CallParamRule给出 //表示方法调用的参数。参数的值或者取自指定名称的XML元素的属性,或者是当前元素包含的原始字符数据。这个规则要求用一个整数指定它在参数列表中的位置。 digester.addCallMethod("web-app/servlet/init-param", "addInitParam", 2); digester.addCallParam("web-app/servlet/init-param/param-name", 0);
到这里,Digester
的功能我们已经简单的了解,其实Digester
能做的远不止这些,更多的比如:添加调试信息,异步解析,配置规则模块等,可以在官网上具体了解,这里不再赘述。
参考链接: